package com.bms.client.utils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author zcx
 * @version 1.0
 * @description 工具类
 * @date 2021/3/21 19:10
 */
@Component
public class RedisUtils {
    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    /**
     *
     * @param tableName 表名
     * @param conditionalQueue 查询队列(可以为空,默认为只有id查询)
     * @param id 当前对象id
     * @param pojo 当前对象
     * @return 状态 true 成功 false 失败 传入条件有误或服务异常
     */
    public Boolean redisInsert(String tableName, Map<String,String> conditionalQueue,String id,Object pojo){
        try {
//            SessionCallback<Object> sessionCallback = new SessionCallback<Object>(){
//                @Override
//                public Object execute(RedisOperations operations) throws DataAccessException {
//                    operations.multi();
//                    operations.opsForValue().set("lw3", 2000);
////                redisTemplate.opsForList().range("think01", 0, -1);   // 事务在没有提交前，不会执行结果，所以这里接收只会得到null
//                    return operations.exec();
//                }
//            };
            if(id==null||"".equals(id)||tableName==null||"".equals(tableName))
                return false;
            StringBuilder tableNameBuilder = new StringBuilder(tableName);
            tableNameBuilder.insert(0,"conditionalQueue|");
            tableNameBuilder.append("|id:").append(id);
            if(conditionalQueue==null||conditionalQueue.size()==0){
                redisTemplate.opsForValue().set(tableNameBuilder.toString(),id);
                redisTemplate.opsForHash().put(tableName,id,pojo);
                return true;
            }
            for(String s:conditionalQueue.keySet()){
                if("".equals(s)||"null".equals(s))
                    s="default";
                tableNameBuilder.append("|").append(s).append(":").append(conditionalQueue.get(s));
            }
//            System.out.println(tableNameBuilder);
            redisTemplate.opsForValue().set(tableNameBuilder.toString(),id);
            redisTemplate.opsForHash().put(tableName,id,pojo);
            //清空分页缓存
            Set<String> keys= redisTemplate.keys("page:" + tableName+"*");
            if(keys!=null&&keys.size()>0){
                redisTemplate.delete(keys);
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     *
     * @param tableName 表名
     * @param id 主键
     * @return 状态 true 删除成功 false 重复删除或服务异常
     */
    public Boolean redisDelete(String tableName,String id){
        boolean b=false;
        try {
            redisTemplate.opsForHash().delete(tableName,id);
            Set<String> keys = redisTemplate.keys("conditionalQueue|" + tableName + "|" + "id:" + id + "*");
            Set<String> keys1 = redisTemplate.keys("page:" + tableName+"*");
            if(keys!=null&&keys.size()>0){
                redisTemplate.delete(keys);
                b=true;
            }
            if(keys1!=null&&keys1.size()>0){
                redisTemplate.delete(keys1);
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return b;
    }
    public Boolean redisUpData(String tableName, Map<String,String> conditionalQueue,String id,Object pojo){
        if(redisDelete(tableName,id)){
            return redisInsert(tableName,conditionalQueue,id,pojo);

        }
        return false;
    }

    /**
     *
     * @param page 页数
     * @param tableName 表名
     * @param conditionalQueue 查询队列
     * @return 返回值
     */
    public Map<String,Object> redisPage(Integer page,String tableName,Map<String,String> conditionalQueue){
        Map<String,Object> map=new HashMap<>();
        if(page==null){
            page=1;
        }
        if(page<=0){
            map.put("code", 200);
            map.put("msg","page不能小于0");
            return map;
        }
        StringBuilder mycConditionalQueue= new StringBuilder();
        if(conditionalQueue==null||conditionalQueue.size()==0){//全查
            Boolean aBoolean = redisTemplate.hasKey("page:" +tableName+":");
            if(aBoolean!=null&&aBoolean){
                getPage(page,tableName, tableName,map);
            }
            Set<Object> keys = redisTemplate.opsForHash().keys(tableName);
            if(setPage("",keys,tableName)){
                getPage(page,tableName, "",map);
            }
        }else {//条件查询
            mycConditionalQueue = new StringBuilder();
            for(String s:conditionalQueue.keySet()){
                String n=conditionalQueue.get(s);
                if("".equals(n)|n==null|"*null*".equals(n)|"null".equals(n)|"**".equals(n))
                    n="*";
                mycConditionalQueue.append(s).append(":").append(n).append("|");
            }
            mycConditionalQueue.deleteCharAt(mycConditionalQueue.length()-1);
            Boolean aBoolean = redisTemplate.hasKey("page:" +tableName+":"+ mycConditionalQueue);
            if(aBoolean!=null&&aBoolean){
                getPage(page,tableName , mycConditionalQueue.toString(),map);
            }
            Set<String> keys0 = redisTemplate.keys("conditionalQueue|" + tableName + "|" + "id:*|"+mycConditionalQueue.toString());
            System.out.println("mycConditionalQueue："+"conditionalQueue|" + tableName + "|" + "id:*|"+mycConditionalQueue);
//            System.out.println(keys0);
            Set<Object> keys=new HashSet<>();
            if (keys0 != null&&keys0.size()>0) {
                for(String s:keys0){
                    keys.add(redisTemplate.opsForValue().get(s));
                }
            }else {
                map.put("code", 200);
                map.put("msg", "查询成功");
                map.put("pageCount",1);  // 查询的记录总页码
                map.put("count",0);     // 当前表中的总条数
                map.put("data",new ArrayList<>());
                map.put("page", page);
                return map;
            }
            if(setPage(mycConditionalQueue.toString(),keys,tableName)){
                getPage(page,tableName, mycConditionalQueue.toString(),map);
            }

        }
        return map;
    }

    private void getPage(int page,String tableName, String conditionalQueue, Map<String, Object> map) {
        Long size = redisTemplate.opsForZSet().size("page:"+tableName+":"+conditionalQueue);
//        System.out.println(size);
        int pageCount=1;
        if(size!=null){
          pageCount = (int)(size - 1) / 10 + 1;
        }
        List<Object> list=new ArrayList<>();
        int xiaBiao = (page - 1) * 10;
        Set<Object> ranges = redisTemplate.opsForZSet().rangeByScore("page:"+tableName+":"+conditionalQueue,0,1000000000, xiaBiao,   10);
        if(ranges!=null){
            for (Object range : ranges) {
                //根据zset的key查询hash对应的数据
                //转为对应的实体类
                Object o = redisTemplate.opsForHash().get(tableName, range);
                if (o==null){
                    continue;
                };
                list.add(o);
            }
        }
        map.put("code", 200);
        map.put("msg", "查询成功");
        map.put("pageCount",pageCount);  // 查询的记录总页码
        map.put("count", size);     // 当前表中的总条数
        map.put("data",list);
        map.put("page", page);
    }

    private Boolean setPage(String conditionalQueue,Set<Object> set,String tableName){
        try {
            if(set==null||set.size()==0){
                return false;
            }
            for(Object id:set){
//                System.out.println(id);
                redisTemplate.opsForZSet().add("page:"+tableName+":"+conditionalQueue,id,Integer.parseInt((String) id));
                redisTemplate.expire("page:"+tableName+":"+conditionalQueue,(int)(Math.random() * 10000000) , TimeUnit.MILLISECONDS);
            }
        } catch (NumberFormatException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

}
